package Config::System::Store;

use Moose;
use aliased 'Config::System::File';
use aliased 'Config::System::Section';

my @Default_Paths = qw(default.properties);

has files => (
    is       => 'ro',
    isa      => 'ArrayRef',
    required => 1,
    default  => sub { [] },
);

has sections => (
    is       => 'ro',
    isa      => 'HashRef',
    required => 1,
    default  => sub { {} },
);

sub BUILD {
    my ($self,$args) = @_;
    $self->add_path($_) for @{ $args->{paths} || \@Default_Paths };
}

sub add_path {
    my ($self, $path) = @_;
    push @{ $self->files }, File->new(path => $path);
}

sub add_property {
    my ($self, $section_name, $property_name, $descriptor) = @_;
    my $section = $self->get_or_make_section($section_name);
    $section->add_property($property_name => $descriptor);
}

sub clone {
    my $self = shift;
    local $_;
    my %sections = %{ $self->sections };
    my $files = [map { $_->clone } @{ $self->files }];
    return ref($self)->new(
        sections => {map { $_ => $sections{$_}->clone($files) } keys %sections},
        files    => $files,
    );
}

for my $method (
    qw(get set set_if_1st set_expression set_expression_if_1st)
) {
    __PACKAGE__->meta->add_method($method => sub {
        my ($self, $section_name, $property_name, $value) = @_;
        $self
            ->get_section($section_name, $property_name)
            ->$method($property_name, $value);
    });
}

sub link {
    my ($self, $link_section_name, $source_section_name) = @_;
    # TODO check circular dependencies in links
    eval "use $link_section_name";
    die "Can't link to [$link_section_name] because $@" if $@;
    my $link_section = $self->sections->{$link_section_name};
    die "Can't link to section [$link_section_name] from [$source_section_name] because $link_section_name does not use Config::System"
        unless $link_section;

    my $source_section = $self->get_or_make_section($source_section_name);
    return $source_section->link($link_section);
}

# private ---------------------------------------------------------------------- 

sub get_section {
    my ($self, $section_name, $property_name) = @_;
    my $section = $self->sections->{$section_name};
    # TODO this error happens when u have not used the configurable class yet
    die "No section [$section_name] for property [$property_name]"
        unless $section;
    return $section;
}

sub get_or_make_section {
    my ($self, $section_name) = @_;
    return
        $self->sections->{$section_name}
        ||=
        Section->new(name => $section_name, files => $self->files)
}

1;

__END__

stores all properties and values, grouped into sections
several could exist at once, with a policy guiding who gets which under which conditions
has a list of configuration files
priority is given to 1st mention of property in section in file
following encounters will be ignored
so 1st files override later ones

todo:add filelist class
